package com.example.redis.util;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Slf4j
public class RedisLockUtil implements Lock {

    private Jedis jedis = SpringUtils.getBean("jedis");
    private static String REDIS_LOCK_KEY = "REDIS_LOCK_KEY_";
    private static String REQUEST_ID = "redis_lock_id_";
    /**
     * 锁超时时间，防止线程在入锁以后，无限的执行等待
     */
    private int EXPIRE_TIME_MSECS = 60 * 1000;

    public RedisLockUtil(String key){
        this.REDIS_LOCK_KEY = this.REDIS_LOCK_KEY + key;
    }
    public RedisLockUtil(String key, String val){
        this.REDIS_LOCK_KEY = this.REDIS_LOCK_KEY + key;
        this.REQUEST_ID = this.REQUEST_ID  + val + ":locked";
    }

    @Override
    public boolean tryLock() {
        try {
            if (jedis.exists(REDIS_LOCK_KEY)) {
                Long setNx = jedis.setnx(REDIS_LOCK_KEY, REQUEST_ID);
                if (setNx == 1) {
                    return Boolean.TRUE;
                }
            }
        } catch (Exception e) {
            log.error("redis tryLock Exception", e);
        }
        return Boolean.FALSE;
    }

    @Override
    public void lock() {
        try {
            if (!tryLock()) {
                SetParams params = new SetParams();
                params.px(EXPIRE_TIME_MSECS).nx();
                jedis.set(REDIS_LOCK_KEY, REQUEST_ID, params);
                log.info(">>>>>>redis lock: {}", jedis.get(REDIS_LOCK_KEY));
            }
        } catch (Exception e) {
            log.error("redis lock Exception", e);
        }
    }

    @Override
    public void unlock() {
        try {
            String delLock = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            jedis.eval(delLock, Collections.singletonList(REDIS_LOCK_KEY), Collections.singletonList(REQUEST_ID));
        } catch (Exception e) {
            log.error("redis unlock Exception", e);
        }
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public Condition newCondition() {
        return null;
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }
}
